package com.genntii.examManager.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.genntii.examManager.common.constant.ExceptionConstant;
import com.genntii.examManager.common.result.PageResult;
import com.genntii.examManager.domain.dto.CourseDTO;
import com.genntii.examManager.domain.dto.CourseUpdateDTO;
import com.genntii.examManager.domain.entity.*;
import com.genntii.examManager.domain.vo.CourseDetailVO;
import com.genntii.examManager.common.exception.CourseNotFoundException;
import com.genntii.examManager.domain.vo.CourseVO;
import com.genntii.examManager.mapper.*;
import com.genntii.examManager.service.CourseService;
import com.genntii.examManager.service.PracticeRecordService;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

@Service
public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements CourseService {

    @Resource
    private CourseMapper courseMapper;

    @Resource
    private TeacherMapper teacherMapper;

    @Resource
    private SubjectMapper subjectMapper;

    @Resource
    private CourseRecordMapper courseRecordMapper;

    @Resource
    private ExamMapper examMapper;

    @Resource
    private PracticeMapper practiceMapper;

    @Resource
    private ExamRecordMapper examRecordMapper;

    @Resource
    private PracticeRecordMapper practiceRecordMapper;

    @Override
    public void updateCourse(Long userId, CourseUpdateDTO courseUpdateDTO) {
        Long teacherId = teacherMapper.getTeacherByUserId(userId).getId();
        courseMapper.updateById(Course.builder()
                .id(courseUpdateDTO.getCourseId())
                .courseName(courseUpdateDTO.getCourseName())
                .subjectId(courseUpdateDTO.getSubjectId())
                .status(courseUpdateDTO.getStatus())
                .startTime(courseUpdateDTO.getStartTime())
                .endTime(courseUpdateDTO.getEndTime())
                .finalExamId(courseUpdateDTO.getFinalExamId())
                .updateTime(LocalDateTime.now())
                .teacherId(teacherId)
                .build());
    }

    @Override
    public void addCourse(Long userId, CourseDTO courseDTO) {
        Long teacherId = teacherMapper.getTeacherByUserId(userId).getId();
        courseMapper.insert(Course.builder()
                .teacherId(teacherId)
                .courseName(courseDTO.getCourseName())
                .subjectId(courseDTO.getSubjectId())
                .startTime(courseDTO.getStartTime())
                .endTime(courseDTO.getEndTime())
                .status((byte) 0)
                .createTime(LocalDateTime.now())
                .updateTime(LocalDateTime.now())
                .build());
    }

    @Override
    public CourseDetailVO getCourseDetailById(Long courseId, Long userId) {

        if (courseMapper.selectById(courseId) == null) {
            throw new CourseNotFoundException("课程不存在");
        }

        Course course = courseMapper.getCourseById(courseId);
        Byte partIn = courseRecordMapper.isPartIn(courseId, userId);
        ArrayList<Map<Integer, Integer>> scoreRank = new ArrayList<>();
        ArrayList<ExamRecord> examHistory15 = examRecordMapper.getExamHistory15(userId);
        if (partIn == 1 && examHistory15 != null) {
            ArrayList<Long> examIds = new ArrayList<>();
            for (ExamRecord examRecord : examHistory15) {
                examIds.add(examRecord.getExamId());
            }
            for (Long id : examIds) {
                ArrayList<ExamRecord> allByExamId = examRecordMapper.getAllByExamId(id);
                ExamRecord examRecord = examRecordMapper.getExamRecordByUserId(userId, id);
                if (examRecord == null || examRecord.getScore() == null) continue;
                for (int i = 0; i < allByExamId.size() - 1; i++) {
                    for (int j = 0; j < allByExamId.size() - 1 - i; j++) {
                        if (allByExamId.get(j).getScore() < allByExamId.get(j + 1).getScore()) {
                            ExamRecord temp = allByExamId.get(j);
                            allByExamId.set(j, allByExamId.get(j + 1));
                            allByExamId.set(j + 1, temp);
                        }
                    }
                }

                scoreRank.add(Map.of(examRecord.getScore(), allByExamId.indexOf(examRecord)+1));
            }
        }

        int a = examRecordMapper.getExamCountUserCompleted(userId);

        return CourseDetailVO.builder()
                .id(courseId)
                .courseName(course.getCourseName())
                .teacherName(teacherMapper.selectById(course.getTeacherId()).getName())
                .subjectName(subjectMapper.selectById(course.getSubjectId()).getSubjectName())
                .startTime(course.getStartTime())
                .endTime(course.getEndTime())
                .studentPartIn(courseRecordMapper.studentPartInCount(courseId))
                .practiceCount(practiceMapper.getPracticeCount(courseId))
                .examCount(examMapper.getExamCount(courseId))
                .isPartIn(partIn)
                .examCountUserCompleted(examRecordMapper.getExamCountUserCompleted(userId))
                .practiceCountUserCompleted(practiceRecordMapper.getPracticeCountUserCompleted(userId))
                .scoreRank(scoreRank)
                .build();
    }

    @Override
    public PageResult<CourseVO> selectCourseVOList(String keyword, Integer pageNum, Integer pageSize, Long userId) {

        ArrayList<Course> courses = courseMapper.getCourseListByKeyword(keyword, (pageNum - 1) * pageSize, pageSize);
        return PageResult.build(getCourseVOS(userId, courses), courseMapper.getCourseTotalByKeyword(keyword));
    }

    @Override
    public PageResult<CourseVO> getCourseVOList(Integer pageNum, Integer pageSize, Long userId) {
        ArrayList<Course> courses = courseMapper.getCourseList((pageNum - 1) * pageSize, pageSize);
        return PageResult.build(getCourseVOS(userId, courses), courseMapper.getCourseTotal());
    }

    @Override
    public PageResult<CourseVO> getLatestCourseList(Integer pageNum, Integer pageSize, Long userId) {
        ArrayList<Course> courses = courseMapper.getCourseListLatest((pageNum - 1) * pageSize, pageSize);
        return PageResult.build(getCourseVOS(userId, courses), courseMapper.getCourseTotal());
    }

    private ArrayList<CourseVO> getCourseVOS(Long userId, ArrayList<Course> courses) {
        ArrayList<Long> courseIds = new ArrayList<>();
        ArrayList<Long> teacherIds = new ArrayList<>();
        for (Course course : courses) {
            courseIds.add(course.getId());
            teacherIds.add(course.getTeacherId());
        }


        if (courses.size() == 0) {
            throw new CourseNotFoundException("未找到课程");
        }
        ArrayList<CourseRecord> courseRecords = courseRecordMapper.isPartInBatch(courseIds, userId);
        Map<Long, CourseRecord> courseRecordMap = new HashMap<>();
        if (courseRecords != null) {
            for (CourseRecord courseRecord : courseRecords) {
                courseRecordMap.put(courseRecord.getCourseId(), courseRecord);
            }
        }

        ArrayList<Teacher> teachers = teacherMapper.getTacherBatch(teacherIds);
        Map<Long, Teacher> teacherMap = new HashMap<>();
        for (Teacher teacher : teachers) {
            teacherMap.put(teacher.getId(), teacher);
        }

        ArrayList<CourseVO> courseVOS = new ArrayList<>();
        for (Course course : courses) {
            courseVOS.add(CourseVO.builder()
                    .id(course.getId())
                    .courseName(course.getCourseName())
                    .teacherName(teacherMap.get(course.getTeacherId()).getName())
                    .practiceCount(practiceMapper.getPracticeCount(course.getId()))
                    .studentPartIn(courseRecordMapper.studentPartInCount(course.getId()))
                    .startTime(course.getStartTime())
                    .endTime(course.getEndTime())
                    .isPartIn((byte) (courseRecordMap.get(course.getId()) != null ? 1 : 0))
                    .build());
        }
        return courseVOS;
    }

    @Override
    public PageResult<CourseVO> getCourseListByTeacher(Integer pageNum, Integer pageSize, Long userId) {
        Teacher t = teacherMapper.getTeacherByUserId(userId);

        ArrayList<Course> courses = courseMapper.getCourseListByTeacher(t.getId(), (pageNum - 1) * pageSize, pageSize);

        ArrayList<CourseVO> courseVOS = new ArrayList<>();
        for (Course course : courses) {
            courseVOS.add(CourseVO.builder()
                    .id(course.getId())
                    .courseName(course.getCourseName())
                    .teacherName(t.getName())
                    .practiceCount(practiceMapper.getPracticeCount(course.getId()))
                    .studentPartIn(courseRecordMapper.studentPartInCount(course.getId()))
                    .startTime(course.getStartTime())
                    .endTime(course.getEndTime())
                    .isPartIn((byte) 2)
                    .build());
        }
        return PageResult.build(courseVOS, courseMapper.getCourseTotalByTeacher(t.getId()));
    }

    @Override
    public PageResult<CourseVO> getCourseListUserPartIn(Integer pageNum, Integer pageSize, Long userId) {
        ArrayList<Long> courseIds = courseRecordMapper.getCourseIdsByUserId(userId);
        if (courseIds.isEmpty()) return PageResult.build(new ArrayList<>(), 0);
        ArrayList<Course> courses = courseMapper.getCourseBatch(courseIds);

        long count = courseRecordMapper.getUserCountByCourse(userId);
        ArrayList<CourseVO> courseVOS = getCourseVOS(userId, courses);

        return PageResult.build(courseVOS, count);
    }
}
